﻿using Unity;
using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;

/************************************************************************************
     * 版权所有(c) 2020  保留所有权利。
     * CLR版本： 4.0.30319.42000
     * 机器名称：DESKTOP-VLH6HNS
     * 公司名称：
     * 命名空间：UWB_SOCKET_TEST.server
     * 文件名：  UWBClient
     * 版本号：  V1.0.0.0
     * 唯一标识：75802f74-2303-490b-b43d-52e0db09adae
     * 当前的用户域：DESKTOP-VLH6HNS
     * 创建人：  Minuy
     * 电子邮箱：minuy17@163.com
     * 创建时间：2020/10/24 17:32:01
     * 描述：
     * =====================================================================
     * 修改时间：2020/10/24 17:32:01
     * 修改人  ： 
     * 版本号  ： V1.0.0.0
     * 描述    ：
    *************************************************************************************/

class UWBClient
{
    /// <summary>
    /// 是否打开调试模式
    /// </summary>
    public bool isDebug = true;
    /// <summary>
    /// 输入流
    /// </summary>
    StreamWriter sw;
    /// <summary>
    /// 输出流
    /// </summary>
    StreamReader sr;
    /// <summary>
    /// 网络流
    /// </summary>
    NetworkStream stream;
    /// <summary>
    /// TCP客户端
    /// </summary>
    TcpClient tcpClient;

    /// <summary>
    /// 锚点
    /// </summary>
    public float anchor1X;
    public float anchor1Y;
    public float anchor1Z;
    public float anchor2X;
    public float anchor2Y;
    public float anchor2Z;
    public float anchor0X;
    public float anchor0Y;
    public float anchor0Z;

    /// <summary>
    /// 目标点
    /// </summary>
    public float tagX;
    public float tagY;
    public float tagZ;
    public int tagId;

    /// <summary>
    /// 标签ID
    /// </summary>
    public int setTagId = 5;

    string host;
    int port;
    string account;
    string pwd;

    /// <summary>
    /// 时间戳缓存
    /// </summary>
    public long times;
    /// <summary>
    /// 是否登录了
    /// </summary>
    public bool isLogin = false;

    /// <summary>
    /// 登录消息
    /// </summary>
    /// <param name="sta">登录状态</param>
    public delegate void LoginMessageHandler(bool sta);
    /// <summary>
    /// 基于上面的委托定义事件
    /// </summary>
    public event LoginMessageHandler LoginMessageEvent;
    /// <summary>
    /// 服务器消息事件，回传服务器返回的消息
    /// </summary>
    /// <param name="msg">服务器消息</param>
    public delegate void ServerMessageHandler(string msg);
    /// <summary>
    /// 基于上面的委托定义事件
    /// </summary>
    public event ServerMessageHandler ServerMessageEvent;


    long timeOut = 10000;
    /// <summary>
    /// 心跳线程
    /// </summary>
    Thread heartbeatThread;
    /// <summary>
    /// 接收线程
    /// </summary>
    Thread receiveThread;
    /// <summary>
    /// 登录线程
    /// </summary>
    Thread loginThread;

    private void LoginSta(bool sta)
    {
        if (!sta)
        {
            if (tcpClient != null)
            {
                tcpClient.Close();
            }
        }

        if (isDebug) DebugOut("————————————登录状态："+ sta);
        isLogin = sta;

        LoginMessageEvent?.Invoke(sta);
    }
    /// <summary>
    /// 设置超时时间，最小1s，单位ms
    /// </summary>
    /// <param name="t"></param>
    public void setTimeOut(long t)
    {
        if (t > 1000)
        {
            timeOut = t;
        }
    }
    /// <summary>
    /// 接收线程，接收获取的数据包
    /// </summary>
    private void ReceiveThread()
    {
        try
        {
            while (tcpClient.Connected)
            {
                string cmd = sr.ReadLine();
                if (isDebug) DebugOut("接收到数据");
                DisposeCmd(cmd);
            }
        }
        catch (Exception)
        {
            LoginSta(false);
        }
    }

    private void DisposeCmd(string cmd)
    {
        string key;
        string body;
        string[] parameters;

        new CmdParser(":", ",").Parse(cmd, out key, out body, out parameters);

        if (isDebug) DebugOut("Key:" + key);

        if (isDebug) DebugOut("Body:" + body);
        if (key == "Anchor")
        {
            //Anchor:n,n,n,n
            if (parameters.Length >= 4)
            {
                if (parameters[0] == "n")
                {
                    //数据为空
                    return;
                }
                else if (parameters[0] == "e")
                {
                    //参数错误
                    return;
                }
                else if (parameters[0] == "1")
                {
                    anchor0X = float.Parse(parameters[1]);
                    anchor0Y = float.Parse(parameters[2]);
                    anchor0Z = float.Parse(parameters[3]);
                }
                else if (parameters[0] == "2")
                {
                    anchor1X = float.Parse(parameters[1]);
                    anchor1Y = float.Parse(parameters[2]);
                    anchor1Z = float.Parse(parameters[3]);
                }
                else if (parameters[0] == "3")
                {
                    anchor2X = float.Parse(parameters[1]);
                    anchor2Y = float.Parse(parameters[2]);
                    anchor2Z = float.Parse(parameters[3]);
                }
            }
        }
        else if (key == "Local")//Local:id,x,y,z
        {
            if (parameters.Length >= 4)
            {
                if (parameters[0] == setTagId + "")
                {
                    tagId = setTagId;
                    tagX = float.Parse(parameters[1]) / 100;
                    tagY = float.Parse(parameters[2]) / 100;
                    tagZ = float.Parse(parameters[3]) / 100;
                }
            }
        }
        else if (key == "LOGIN")
        {
            if (parameters.Length > 0)
            {
                if (parameters[0] == "OK")
                {
                    //登录成功
                    LoginSta(true);

                    //开启心跳线程
                    ThreadStart heartbeat = new ThreadStart(HeartbeatThread);
                    heartbeatThread = new Thread(heartbeat);
                    heartbeatThread.Start();
                }
                else
                {
                    //登录失败
                    LoginSta(false);
                }
            }
        }
        else if (key == "HEARTBEAT")
        {
            if (parameters.Length > 0)
            {
                if (parameters[0] == "OK")
                {
                    if (isDebug) DebugOut("________________心跳正常__________________________");
                    //心跳正常
                    times = this.GetTimestamp();
                }
                else
                {
                    //登录失败
                    LoginSta(false);
                }
            }
        }
        else if (key == "LOGOUT")
        {
            if (parameters.Length > 0)
            {
                if (parameters[0] == "BEY")
                {
                    LoginSta(false);
                }
            }
        }
        else if (ServerMessageEvent != null)
        {
            //其他消息
            ServerMessageEvent(cmd);
        }
    }

    /// <summary>
    /// 心跳线程，定时给服务器发心跳包
    /// </summary>
    private void HeartbeatThread()
    {
        int i = 0;
        times = this.GetTimestamp();
        while (tcpClient.Connected)
        {
            Thread.Sleep(300);
            if (i > 9)
            {
                i = 0;
                SocketSend("Heartbeat:" + this.account);
                if (this.GetTimestamp() - times > 9000)
                {
                    //6s没回，断线
                    LoginSta(false);

                }
            }

            if (i % 7 == 0)
            {
                SocketSend("GetAnchor:" + this.account + ",1");
                SocketSend("GetAnchor:" + this.account + ",2");
                SocketSend("GetAnchor:" + this.account + ",3");
            }
            SocketSend("GetLocal:" + this.account + "," + setTagId);

            i++;
        }
        if (isDebug) DebugOut("________________心跳退出");
        LoginSta(false);
    }


    /// <summary>
    /// 重载登录，使用当前信息，方便重连服务器
    /// </summary>
    public void Login()
    {
        this.Login(this.host, this.port, this.account, this.pwd);
    }

    public void Login(string host, string port, string name, string pwd)
    {
        try
        {
            int ports = int.Parse(port);

            this.port = ports;
            this.account = name;
            this.pwd = pwd;
            this.host = host;

            this.Login(this.host, this.port, this.account, this.pwd);
        }
        catch (FormatException)
        {
            if (isDebug) DebugOut("解析端口失败");
            LoginSta(false);
            //return false;
        }
    }

    /// <summary>
    /// 根据所提供的信息登录服务器
    /// </summary>
    /// <param name="host">主机名</param>
    /// <param name="port">端口号</param>
    /// <param name="name">账号</param>
    /// <param name="pwd">密码</param>
    public void Login(string host, int port, string name, string pwd)
    {
        this.port = port;
        this.account = name;
        this.pwd = pwd;
        this.host = host;

        //开启登录线程
        ThreadStart login = new ThreadStart(LoginThread);
        this.loginThread = new Thread(login);
        this.loginThread.Start();

    }

    private void LoginThread()
    {
        try
        {
            string cmd = "Login:" + this.account + "," + this.pwd;


            if (isDebug) DebugOut("准备登录");

            if (IsLink())
            {
                if (isDebug) DebugOut("已连接");
                this.SocketSend(cmd);
                //return true;
            }

            if (this.host == null || this.account == null || this.pwd == null)
            {

                if (isDebug) DebugOut("空字符串");
                this.LoginSta(false);
                //return false;
            }

            if (this.account.IndexOf(",") != -1)
            {
                //非法字符
                if (isDebug) DebugOut("非法字符");
                this.LoginSta(false);
                //return false;
            }

            if (this.pwd.IndexOf(",") != -1)
            {
                //非法字符
                if (isDebug) DebugOut("非法字符");
                this.LoginSta(false);
                // return false;
            }

            this.tcpClient = new TcpClient(host, port);  // 连接服务器
            if (this.tcpClient.Connected)
            {
                if (isDebug) DebugOut("连接服务器成功");
                //连接服务器成功

                this.stream = this.tcpClient.GetStream();   // 获取网络数据流对象
                this.sw = new StreamWriter(stream);
                this.sr = new StreamReader(stream);


                if (isDebug) DebugOut("开启服务器线程");

                //开启接收线程
                ThreadStart receive = new ThreadStart(ReceiveThread);
                this.receiveThread = new Thread(receive);
                this.receiveThread.Start();

                //发送登录命令
                this.SocketSend(cmd);

                //return true;
            }
            else
            {
                if (isDebug) DebugOut("连接服务器失败");
                LoginSta(false);
                //return false;
            }
        }
        catch (SocketException)
        {
            if (isDebug) DebugOut("连接服务器失败！");
            LoginSta(false);
            //return false;
        }
        catch (ArgumentException)
        {
            if (isDebug) DebugOut("服务器地址错误！");
            LoginSta(false);
        }
        catch (Exception)
        {
            if (isDebug) DebugOut("服务器其他错误！");
            LoginSta(false);
        }
    }

    public void Login(string name, string pwd)
    {
        this.account = name;
        this.pwd = pwd;
        this.Login();
    }

    private bool IsLink()
    {
        if (tcpClient != null)
        {
            if (tcpClient.Connected)
            {
                return true;
            }
        }
        return false;
    }

    /*
    /// <summary>
    /// 连接服务器
    /// </summary>
    /// <param name="server">服务器</param>
    /// <param name="port">服务器端口</param>
    /// <returns>一个已经连接的Socket或者null</returns>
    private TcpClient ConnectServer(string server, int port)
    {
        TcpClient s = null;
        IPHostEntry hostEntry = null;

        // 获取主机相关信息。
        hostEntry = Dns.GetHostEntry(server);

        // 循环通过AddressList获得支持的AddressFamily。这是为了避免主机IP地址与地址族不兼容时发生的异常（在IPv6情况下是典型的）。
        foreach (IPAddress address in hostEntry.AddressList)
        {
            try
            {
                IPEndPoint ipe = new IPEndPoint(address, port);
                TcpClient tempSocket =
                    new TcpClient(ipe.AddressFamily);

                tempSocket.Connect(ipe);

                if (tempSocket.Connected)
                {
                    s = tempSocket;
                    break;
                }
                else
                {
                    continue;
                }
            }
            catch (Exception)
            {

            }
        }
        return s;
    }

    */
    /// <summary>
    /// 给服务器发送消息，自动添加换行回车
    /// </summary>
    /// <param name="str">发送的消息</param>
    private void SocketSend(string str)
    {
        /*
        if (isDebug) DebugOut("准备发送");
        if (!IsLink())
        {
            if (isDebug) DebugOut("没有连接");
            return;
        }
        */
        try
        {
            if (sw != null)
            {
                if (isDebug) DebugOut("发送数据" + str);
                sw.Write(str + "\r\n");
                sw.Flush();
            }
        }
        catch (Exception)
        {
            LoginSta(false);
        }
    }


    internal void LogOut()
    {
        SocketSend("LogOut");
    }
    /// <summary>
    /// 获取时间戳
    /// </summary>
    /// <returns>长整型时间戳</returns>
    private long GetTimestamp()
    {
        return Timestamp.GetTimeStamp();
    }


    private void DebugOut(string str)
    {
        Debug.Log(str);
    }
}